﻿Imports System.Net
Imports System.Net.Sockets

Public Class NetAsyncClient

    Public client As Socket
    Private buffer(256) As Byte

    Public Event OnReceiveData(ByVal inBuffer() As Byte, ByVal inSizeBuffer As Integer)
    Public strErrorMsg As String

    Public Function Connect(ByVal inHost As String, ByVal inPort As Integer) As Boolean
        Try

            ' Close the socket if it is still open
            If client IsNot Nothing AndAlso client.Connected Then
                client.Shutdown(Sockets.SocketShutdown.Both)
                Threading.Thread.Sleep(10)
                client.Close()
            End If

            ' Create the socket object
            client = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

            ' Define the Server address and port
            Dim epServer As IPEndPoint = New IPEndPoint(IPAddress.Parse(inHost), inPort)

            ' Connect to the server blocking method and setup callback for recieved data
            ' m_sock.Connect( epServer );
            ' SetupRecieveCallback( m_sock );

            ' Connect to server non-Blocking method
            client.Blocking = False
            Dim onConnectCallBack As AsyncCallback = New AsyncCallback(AddressOf OnConnect)
            client.BeginConnect(epServer, onConnectCallBack, client)

            Return True
        Catch ex As Exception
            strErrorMsg = ex.Message
            Return False
        End Try

    End Function

    Public Function Send(ByVal inData() As Byte) As Boolean
        ' Check is is connected
        If client Is Nothing OrElse Not client.Connected Then
            strErrorMsg = "Socket not connected"
            Return False
        End If

        ' Send message
        Try
            client.Send(inData, inData.Length, SocketFlags.None)

            Return True
        Catch ex As Exception
            strErrorMsg = ex.Message
            Return False
        End Try

    End Function

    Public Function IsConnected() As Boolean
        If client IsNot Nothing Then
            Return client.Connected
        Else
            Return False
        End If
    End Function

    Private Function OnConnect(ByVal inAsyncRes As IAsyncResult) As Boolean
        Try
            Dim localSocket As Socket = CType(inAsyncRes.AsyncState, Socket)

            If localSocket.Connected Then
                Call SetupRecieveCallback(localSocket)
            Else
                strErrorMsg = "Unable to connect to remote machine"
                Return False
            End If

            Return True
        Catch ex As Exception
            strErrorMsg = ex.Message
            Return False
        End Try

    End Function

    Private Function SetupRecieveCallback(ByRef inSocket As Socket) As Boolean
        Try

            Dim onReceiveDataCallBack As AsyncCallback = New AsyncCallback(AddressOf OnRecievedData)
            inSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, onReceiveDataCallBack, inSocket)

            Return True
        Catch ex As Exception
            strErrorMsg = ex.Message
            Return False
        End Try
    End Function

    Private Function OnRecievedData(ByVal inAsyncRes As IAsyncResult) As Boolean
        Try
            Dim localSocket As Socket = CType(inAsyncRes.AsyncState, Socket)
            Dim numBytesRec As Integer = localSocket.EndReceive(inAsyncRes)

            If numBytesRec > 0 Then
                ' Call event 
                RaiseEvent OnReceiveData(buffer, numBytesRec)

                ' If the connection is still usable restablish the callback
                SetupRecieveCallback(localSocket)
            Else
                ' If no data was recieved then the connection is probably dead
                strErrorMsg = String.Format("Client {0}, disconnected", localSocket.RemoteEndPoint)
                localSocket.Shutdown(SocketShutdown.Both)
                localSocket.Close()
                Return False
            End If

            Return True
        Catch ex As Exception
            strErrorMsg = ex.Message
            Return False
        End Try

    End Function

End Class
